package com.example.travel.controller;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.travel.common.AjaxResult;
import com.example.travel.common.AuthAccess;
import com.example.travel.common.TableDataInfo;
import com.example.travel.domain.entity.Menu;
import com.example.travel.domain.entity.User;
import com.example.travel.domain.entity.UserSpot;
import com.example.travel.domain.entity.Validation;
import com.example.travel.domain.request.EmailRequestVo;
import com.example.travel.domain.request.LoginEmailRequest;
import com.example.travel.domain.request.LoginUserRequest;
import com.example.travel.domain.request.RegisterUserVo;
import com.example.travel.domain.request.PageQuery;
import com.example.travel.domain.request.UserPasswordDTO;
import com.example.travel.domain.request.UserPasswordVo;
import com.example.travel.domain.response.UserDto;
import com.example.travel.interceptor.TokenUtils;
import com.example.travel.mapper.RoleMenuMapper;
import com.example.travel.mapper.UserSpotMapper;
import com.example.travel.service.MenuService;
import com.example.travel.service.RoleService;
import com.example.travel.service.UserService;
import com.example.travel.service.ValidationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;

/**
 * @Author : LinQingLiang
 * @file : UserController.java
 * @Since : 2023/1/13 16:27
 */

@RestController
@Api(tags = "用户管理")
@RequestMapping("/user")
public class UserController extends BaseController{


    @Autowired
    private ValidationService validationService;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private MenuService menuService;

    @Autowired
    private UserSpotMapper userSpotMapper;

    Logger logger = LoggerFactory.getLogger(getClass());


    //分页查询
    @GetMapping("list")
    public TableDataInfo list(@Validated PageQuery pageQuery, User user){
//        User currentUser = TokenUtils.getUser();
        Page page1 = userService.page(user, pageQuery.getPageNum(),pageQuery.getPageSize());
        return getDataTable(page1.getRecords(),page1.getTotal());
    }

    //添加
    @PostMapping("add")
    public AjaxResult create(@RequestBody User user){
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("username",user.getUsername());
        User row = userService.getOne(wrapper);
        if (row != null){
            return AjaxResult.error("用户名已存在");
        }
        wrapper.eq("password",user.getPassword());
        User row2 = userService.getOne(wrapper);
        if (row2 != null){
            return AjaxResult.error("密码已存在");
        }
        return toAjax(userService.save(user));
    }

    //修改前查询
    @GetMapping("{userId}")
    public AjaxResult selectById(@PathVariable Integer userId){
        return AjaxResult.success(userService.getById(userId));
    }

    //修改
    @PutMapping("updateUser")
    public AjaxResult updateUser(@RequestBody User user){
        QueryWrapper<User> wrapper = new QueryWrapper();
        wrapper.eq("username",user.getUsername());
        User user1 = userService.getOne(wrapper);
        if (user1 != null && !(user.getUsername()).equals(user1.getUsername())){
            return AjaxResult.error("用户名已经存在不能进行修改");
        }
        return toAjax(userService.updateById(user));
    }

    //删除个人
    @DeleteMapping("deleteUser/{userId}")
    public AjaxResult deleteUser(@PathVariable Integer userId){
        LambdaQueryWrapper<User> lambdaQueryWrapper = new LambdaQueryWrapper();
        lambdaQueryWrapper.eq(User::getId,userId);
        return AjaxResult.success(userService.remove(lambdaQueryWrapper));
    }

    //批量删除
    @DeleteMapping("deleteUsers/{userIds}")
    public AjaxResult deleteUser(@PathVariable List<Integer> userIds){
        return AjaxResult.success(userService.removeBatchByIds(userIds));
    }

    /**
     * 表格导出
     * @param response
     * @throws Exception
     */
    @GetMapping("/export")
    public void export(HttpServletResponse response) throws Exception {
        List<User> list = userService.list();

        //在内存操作，写出到浏览器
        ExcelWriter writer = ExcelUtil.getWriter(true);
        //自定义标签别名
        writer.addHeaderAlias("username","用户名");
        writer.addHeaderAlias("password","密码");
        writer.addHeaderAlias("nickName","昵称");
        writer.addHeaderAlias("email","邮箱");
        writer.addHeaderAlias("phone","电话");
        writer.addHeaderAlias("address","地址");
        writer.addHeaderAlias("createTime","创建时间");
        writer.addHeaderAlias("avatarUrl","头像");

        //一次性写出list的对象到excel
        writer.write(list,true);

        //设置浏览器的相应格式
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息","UTF-8");
        response.setHeader("Content-Disposition","attachment;filename="+fileName+".xlsx");

        ServletOutputStream out = response.getOutputStream();
        writer.flush(out,true);
        out.close();
        writer.close();
    }


    @PostMapping("/import")
    public AjaxResult importExcel(MultipartFile file) throws Exception{
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        //通过javabean的方式读取对象，但是表头必须要求是英文，要跟实体类的属性对应起来
//        List<User> list = reader.readAll(User.class);

        //加表头注释，直接读取
        List<List<Object>> list = reader.read(1);
        List<User> users = CollUtil.newArrayList();
        for(List<Object> row:list){
            User user = new User();
            user.setUsername(row.get(0).toString());
            user.setPassword(row.get(1).toString());
            user.setNickName(row.get(2).toString());
            user.setEmail(row.get(3).toString());
            user.setAddress(row.get(4).toString());
            user.setPhone(row.get(5).toString());
            user.setAvatarUrl(row.get(6).toString());
            users.add(user);
        }
        return AjaxResult.success(userService.saveBatch(users));
    }


    @PostMapping("/login")
    @ApiOperation(value = "登录",notes = "用户进行账号登录接口")
    public AjaxResult login(@Validated @RequestBody LoginUserRequest loginUserRequest){

        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(User::getUsername,loginUserRequest.getUsername())
                .eq(User::getPassword,loginUserRequest.getPassword());

        try {
            User user = userService.getOne(lambdaQueryWrapper);
            if (user == null){
                return AjaxResult.error(50020,"账号密码有误");
            }else{
                UserDto userDto = new UserDto();
                BeanUtil.copyProperties(user,userDto,true);
                //设置token
                String token = TokenUtils.getToken(user.getId().toString(),user.getPassword());
                userDto.setToken(token);

                String role = user.getRole();
                Integer roleId = roleService.selectByFlag(role);

                List<Menu> roleMenus = getRoleMenus(roleId);
                userDto.setMenus(roleMenus);
                return AjaxResult.success(userDto);
            }
        }catch (Exception e){
            logger.error("登录失败："+e);
            return AjaxResult.error(50020,"当前账号是脏数据");
        }
    }


    @AuthAccess
    @GetMapping("/email/send")
    public AjaxResult sendEmail(EmailRequestVo emailRequestVo) throws MessagingException {
        if (StrUtil.isBlank(emailRequestVo.getEmail())){
            return AjaxResult.error(400,"参数错误");
        }
        if (emailRequestVo.getType() == null){
            return AjaxResult.error(400,"参数错误");
        }
        return userService.sendEmail(emailRequestVo.getEmail(),emailRequestVo.getType());
    }


    @AuthAccess
    @PostMapping("/loginEmail")
    @ApiOperation(value = "登录",notes = "用户进行邮箱验证登录")
    public AjaxResult loginEmail(@Validated @RequestBody LoginEmailRequest loginEmailRequest){

        LambdaQueryWrapper<Validation> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(Validation::getEmail,loginEmailRequest.getEmail())
                .eq(Validation::getCode,loginEmailRequest.getCode())
                .ge(Validation::getTime,new Date());

        try {
            Validation validation = validationService.getOne(lambdaQueryWrapper);
            if (validation == null){
                return AjaxResult.error(-1,"当前验证码已经过期，请重新获取");
            }else{

                //验证通过再去查询用户信息
                QueryWrapper<User> wrapper = new QueryWrapper<>();
                wrapper.eq("email",loginEmailRequest.getEmail());
                User user = userService.getOne(wrapper);

                if(user == null){
                    return AjaxResult.error("未找到改用户");
                }

                UserDto userDto = new UserDto();
                BeanUtil.copyProperties(user,userDto,true);
                //设置token
                String token = TokenUtils.getToken(user.getId().toString(),user.getPassword());
                userDto.setToken(token);

                String role = user.getRole();
                Integer roleId = roleService.selectByFlag(role);

                List<Menu> roleMenus = getRoleMenus(roleId);
                userDto.setMenus(roleMenus);
                return AjaxResult.success(userDto);
            }
        }catch (Exception e){
            logger.error("登录失败："+e);
            return AjaxResult.error(-1,"当前账号是脏数据");
        }
    }

    /**
     * 根据邮箱重置密码
     * @param userPasswordDTO
     * @return
     */
    @AuthAccess
    @PostMapping("/reset")
    public AjaxResult reset(@RequestBody UserPasswordDTO userPasswordDTO) {
        if (StrUtil.isBlank(userPasswordDTO.getEmail()) || StrUtil.isBlank(userPasswordDTO.getCode())) {
            return AjaxResult.error(-1,"参数出现问题");
        }
        // 先查询 邮箱验证的表，看看之前有没有发送过  邮箱code，如果不存在，就重新获取
        QueryWrapper<Validation> validationQueryWrapper = new QueryWrapper<>();
        validationQueryWrapper.eq("email", userPasswordDTO.getEmail());
        validationQueryWrapper.eq("code", userPasswordDTO.getCode());
        validationQueryWrapper.ge("time", new Date());  // 查询数据库没过期的code, where time >= new Date()
        Validation one = validationService.getOne(validationQueryWrapper);
        if (one == null) {
            return AjaxResult.error(-1,"验证码已经过期，请重新获取");
        }

        // 如果验证通过了，就查询要不过户的信息
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.eq("email", userPasswordDTO.getEmail());  //存根据email查询用户信息
        User user = userService.getOne(userQueryWrapper);

        // 重置密码
        user.setPassword("123");
        userService.updateById(user);
        return AjaxResult.success();
    }

    @PostMapping("/register")
    @ApiOperation(value = "注册",notes = "用户进行注册")
    public AjaxResult register(@RequestBody @Validated RegisterUserVo registerUserVo){

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",registerUserVo.getEmail());
        User user1 = userService.getOne(queryWrapper);
        if (user1 != null){
            return AjaxResult.error(-1,"当前邮箱已经注册");
        }

        QueryWrapper<Validation> wrapper = new QueryWrapper<>();
        wrapper.eq("type",registerUserVo.getType());
        wrapper.eq("email",registerUserVo.getEmail());
        Validation one = validationService.getOne(wrapper);
        if (one != null){
            Validation validation = validationService.getOne(wrapper);
            wrapper.eq("code", registerUserVo.getCode());
            wrapper.ge("time", new Date());  // 查询数据库没过期的code, where time >= new Date()
            Validation validation1 = validationService.getOne(wrapper);
            if (validation1 == null) {
                return AjaxResult.error(-1,"验证码已经过期，请重新获取");
            }
            LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
            lambdaQueryWrapper.eq(User::getUsername,registerUserVo.getUsername())
                    .eq(User::getPassword,registerUserVo.getPassword());

            User user = userService.getOne(lambdaQueryWrapper);
            if (user == null){
                user = new User();
                BeanUtil.copyProperties(registerUserVo,user,true);
                if(userService.save(user)){
                    return AjaxResult.success(user);
                }else{
                    return AjaxResult.error("添加失败");
                }
            }else{
                return AjaxResult.error(-1,"当前账号已经存在");
            }
        }
        return AjaxResult.error(-1,"请先发送邮箱");
    }


    @GetMapping("/getUserInfo/{username}")
    @ApiOperation(value = "个人信息",notes = "查询个人用户信息")
    public AjaxResult getUserInfo(@PathVariable String username){
        LambdaQueryWrapper<User> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(User::getUsername,username);
        User user = userService.getOne(lambdaQueryWrapper);
        if (user != null){
            return AjaxResult.success(user);
        }
        return AjaxResult.error("没有当前用户");
    }


    /**
     * 根据用户角色查询当前用户信息
     * @param role
     * @return
     */
    @GetMapping("/role/{role}")
    public AjaxResult selectUserByRole(@PathVariable String role){
        LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(User::getRole,role);
        return AjaxResult.success(userService.list(wrapper));
    }


    /**
     * 获取当前角色的菜单列表
     * @param roleId
     * @return
     */
    private List<Menu> getRoleMenus(Integer roleId){
        //当前角色的所有菜单集合
        List<Integer> menuIds = roleMenuMapper.selectByRoleId(roleId);

        //查出系统所有菜单
        List<Menu> menus = menuService.findMenus("");
        //new最后筛选出来的list
        List<Menu> roleMenus = new ArrayList<>();

        for (Menu menu:menus) {
            if (menuIds.contains(menu.getId())){
                roleMenus.add(menu);
            }
            List<Menu> children = menu.getChildren();
            children.removeIf(child -> !menuIds.contains(child.getId()));
        }
        return roleMenus;
    }


    //分页查询
    @GetMapping("userList")
    public TableDataInfo userList(@Validated PageQuery pageQuery, Integer id){
        Page page1 = userService.shopUser(id, pageQuery.getPageNum(),pageQuery.getPageSize());
        return getDataTable(page1.getRecords(),page1.getTotal());
    }


    @GetMapping("/deleteUserSpot/{userSpotId}")
    public AjaxResult deleteById(@PathVariable Integer userSpotId){
        userService.deleteByUserSpotId(userSpotId);
        return AjaxResult.success();
    }


    @PostMapping("/password")
    public AjaxResult password(@RequestBody UserPasswordVo userPasswordVo){
        userService.updatePassword(userPasswordVo);
        return AjaxResult.success();
    }


    @GetMapping("/collect/{userId}")
    public AjaxResult userCollected(@PathVariable Integer userId){
        return AjaxResult.success(userService.userCollected(userId));
    }

    @GetMapping("/insertCollect/{spotId}")
    public AjaxResult insertCollected(@PathVariable Integer spotId){
        Integer userId = TokenUtils.getUser().getId();
        QueryWrapper<UserSpot> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id",userId).eq("spot_id",spotId);
        UserSpot userSpot = userSpotMapper.selectOne(wrapper);
        if (userSpot != null){
            return AjaxResult.error("当前景点已经收藏");
        }else{
            UserSpot userSpot1 = new UserSpot();
            userSpot1.setUserId(userId);
            userSpot1.setSpotId(spotId);
            userSpotMapper.insert(userSpot1);
            return AjaxResult.success("收藏成功");
        }
    }

    /**
     *取消景点收藏
     * @param spotIds
     * @return
     */
    @DeleteMapping("deleteCollects/{spotIds}")
    public AjaxResult deleteCollects(@PathVariable List<Integer> spotIds){
        Integer userId = TokenUtils.getUser().getId();
        return AjaxResult.success(userSpotMapper.deleteBySpotIds(spotIds,userId));
    }

}
